﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Text;

using alib.Collections;
using alib.Debugging;
using alib.Reflection;

namespace agree
{
	public static class _count_ext
	{
		public static int Count<T>(this IEnumerable<T> seq)
		{
			throw new Exception("use _Count() in alib.Enumerable instead");
		}
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// various exception types
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	public abstract class agree_exception : Exception
	{
		agree_exception() { }
		agree_exception(String msg, Exception ex_inner)
			: base(msg, ex_inner)
		{
#if DEBUG
			capture_stack();
#endif
		}
		agree_exception(Exception ex_inner, String fmt, params Object[] args)
			: this(String.Format(fmt, args), ex_inner)
		{
		}
		agree_exception(String fmt, params Object[] args)
			: this(default(Exception), fmt, args)
		{
		}

#if DEBUG
		[MethodImpl(MethodImplOptions.NoInlining)]
		void capture_stack()
		{
			var st = new StackTrace(2, true);
			var fr = st.GetFrame(0);
			byte[] il = fr.GetMethod().GetMethodBody().GetILAsByteArray();
			if (il[fr.GetILOffset()] != OpCodes.Throw.Value)
				this.stack_trace = st;
		}
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		StackTrace stack_trace;
		public override String StackTrace
		{
			get { return stack_trace != null ? stack_trace.ToString() : base.StackTrace; }
		}

		[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
		_frame[] _dbg
		{
			get
			{
				return stack_trace != null ?
					stack_trace.GetFrames().Select(sf => new _frame(sf)).ToArray() :
					Collection<_frame>.None;
			}
		}
#endif
		struct _frame
		{
			const String c1 = @"D:\Programming\analytical-grammar";
			const String c2 = @"C:\Programming\analytical-grammar";
			public _frame(StackFrame sf)
			{
				MethodBase mi = sf.GetMethod();
				String s = sf.GetFileName();
				if (String.IsNullOrEmpty(s))
				{
					this.filename = null;
					this.line = 0;
					this.method = mi.FullName();
				}
				else
				{
					if (s.StartsWith(c1) || s.StartsWith(c2))
						s = s.Substring(c1.Length);
					this.filename = s;
					this.line = sf.GetFileLineNumber();
					this.method = mi.Name;
				}
			}
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			String filename;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			String method;
			[DebuggerBrowsable(DebuggerBrowsableState.Never)]
			int line;
			public override string ToString()
			{
				if (filename != null)
					return String.Format("{0,-25} {1} {2}", method, filename, line);
				else
					return method;
			}
		}

		public abstract class Warning : agree_exception
		{
			public Warning(String msg) : base(msg) { }
			public Warning(Exception ex_inner, String fmt, params Object[] args) : base(ex_inner, fmt, args) { }
		};

		public abstract class NonRestartable : agree_exception
		{
			public NonRestartable() : base() { }
			public NonRestartable(String msg) : base(msg) { }
			//public NonRestartable(String msg, Exception ex_inner) : base(msg, ex_inner) { }
			public NonRestartable(Exception ex_inner, String fmt, params Object[] args) : base(ex_inner, fmt, args) { }
		};
	};

	//public class XamlTypeException : Exception
	//{
	//	public XamlTypeException(System.Type type)
	//		: base(String.Format("AgreeXaml cannot create an instance of type '{0}' because '{0}' does not implement interface '{1}'",
	//				type.Name,
	//				typeof(IInstance).Name))
	//	{
	//	}
	//};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	public class Warning : agree_exception.Warning
	{
		public Warning(String fmt, params Object[] args) : base(default(Exception), fmt, args) { }
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	public class PipelineConfigurationException : agree_exception.NonRestartable
	{
		public PipelineConfigurationException(String msg) : base(msg) { }
	};

	public sealed class XamlLoadException : agree_exception.NonRestartable
	{
		public XamlLoadException(Exception ex_inner, String fmt, params Object[] args)
			: base(ex_inner, fmt, args)
		{
		}
	};

	public sealed class MarkupException : agree_exception.NonRestartable
	{
		public MarkupException(String fmt, params Object[] args)
			: base(default(Exception), fmt, args)
		{
		}
	};

	public class TdlException : agree_exception.NonRestartable
	{
		String filename;
		int line;
		int column;

		public TdlException(String fmt, params Object[] args)
			: base(default(Exception), fmt, args)
		{
		}
		public TdlException(FilePos ep, String fmt, params Object[] args)
			: this(fmt, args)
		{
			this.filename = ep.file;
			this.line = ep.line;
			this.column = ep.col;
		}
		//public TdlException(TdlTok ep, String fmt, params Object[] args)
		//	: this(ep.FilePos, fmt, args)
		//{
		//}
	};

	public class TypeManagerException : agree_exception.NonRestartable
	{
		public TypeManagerException(String fmt, params Object[] args)
			: base(default(Exception), fmt, args)
		{
		}
	};

	public class RewriterException : agree_exception.NonRestartable
	{
		public RewriterException(String fmt, params Object[] args)
			: base(default(Exception), fmt, args)
		{
		}
	};

	public class ReppException : agree_exception.NonRestartable
	{
		public ReppException(String fmt, params Object[] args)
			: base(default(Exception), fmt, args)
		{
		}
	};

	public class ConfigException : agree_exception.NonRestartable
	{
		public ConfigException(String fmt, params Object[] args)
			: base(default(Exception), fmt, args)
		{
		}
	};

	public class GrammarLoadException : agree_exception.NonRestartable
	{
		public GrammarLoadException(String fmt, params Object[] args)
			: base(default(Exception), fmt, args)
		{
		}
	};

	public class LexiconException : GrammarLoadException
	{
		public LexiconException(String fmt, params Object[] args)
			: base(fmt, args)
		{
		}
	};

	public sealed class GrammarAuxiliaryFileException : GrammarLoadException
	{
		public GrammarAuxiliaryFileException(String fmt, params Object[] args)
			: base(fmt, args)
		{
		}
	};

	public class TransferGrammarLoadException : agree_exception.NonRestartable
	{
		public TransferGrammarLoadException(String fmt, params Object[] args)
			: base(default(Exception), fmt, args)
		{
		}
	};

	public class ConsistencyException : agree_exception.NonRestartable
	{
		public ConsistencyException(String fmt, params Object[] args)
			: base(default(Exception), fmt, args)
		{
		}
	};

	public class TfsException : agree_exception.NonRestartable
	{
		public TfsException(String msg)
			: base(msg)
		{
		}
		public TfsException(String fmt, params Object[] args)
			: base(default(Exception), fmt, args)
		{
		}
	};

	public class RedundantGraphLinksException : agree_exception.NonRestartable
	{
		public RedundantGraphLinksException(String msg) : base(msg) { }
	};

	public class RequiredPropertyNotSetException : agree_exception.NonRestartable
	{
		public RequiredPropertyNotSetException(System.Type type, String property_name)
			: base(null, "Cannot use the object because the required property '{0}.{1}' is not set.", type._Name(), property_name)
		{
		}
		[MethodImpl(MethodImplOptions.NoInlining)]
		public RequiredPropertyNotSetException(String property_name)
			: this(new StackTrace().CallingType(), property_name)
		{
		}
	};

	public class PropertyAlreadySetException : agree_exception.NonRestartable
	{
		public PropertyAlreadySetException(System.Type type, String property_name)
			: base(null, "The write-once property '{0}.{1}' has already been set.", type._Name(), property_name)
		{
		}
		[MethodImpl(MethodImplOptions.NoInlining)]
		public PropertyAlreadySetException(String property_name)
			: this(new StackTrace().CallingType(), property_name)
		{
		}
	};

	public class CancelJobException : agree_exception.NonRestartable
	{
		public CancelJobException()
			: this(null)
		{
		}
		public CancelJobException(Exception inner)
			: base(inner, "internal use")
		{
		}
	};

	public class ParseException : agree_exception.NonRestartable
	{
		public ParseException(String fmt, params Object[] args)
			: base(fmt == null || args.Length == 0 ? fmt ?? String.Empty : String.Format(fmt, args))
		{
		}
		public ParseException()
		{
		}
	};

	public class ParseTimeoutException : ParseException
	{
		public ParseTimeoutException()
		{
		}
		public ParseTimeoutException(String fmt, params Object[] args)
			: base(fmt, args)
		{
		}
	};

	public class JobMemoryExceededException : ParseException
	{
		public JobMemoryExceededException()
		{
		}
		public JobMemoryExceededException(String fmt, params Object[] args)
			: base(fmt, args)
		{
		}
	};

	public class DerivationLimitExceededException : ParseException
	{
		public DerivationLimitExceededException()
		{
		}
		public DerivationLimitExceededException(String fmt, params Object[] args)
			: base(fmt, args)
		{
		}
	};

	public class LexicalAnalysisException : ParseException
	{
		public LexicalAnalysisException(String fmt, params Object[] args)
			: base(fmt, args)
		{
		}
	};

	public class LexicalCoverageException : ParseException
	{
		public LexicalCoverageException(String fmt, params Object[] args)
			: base(fmt, args)
		{
		}
	};



}